#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import tempfile
import logging
import shutil
import uuid
from typing import Dict, Any, BinaryIO, List, Optional
from fastapi import UploadFile

from document_processor.engine_factory import EngineFactory
from image_handler.obs_uploader import OBSUploader

logger = logging.getLogger(__name__)

class DocumentService:
    """文档处理服务
    
    处理文档转换、Markdown生成和图片处理等功能。
    """
    
    def __init__(self, config: Dict[str, Any]):
        """初始化文档处理服务
        
        Args:
            config: 配置字典
        """
        self.config = config
        self.obs_uploader = OBSUploader(config)
        
        # 从配置文件读取默认引擎
        self.default_engine = config["document"].get("default_engine", "markitdown")
        
        # 确保所需目录存在
        self.uploads_dir = config["storage"]["uploads_dir"]
        self.output_dir = config["storage"]["output_dir"]
        self.temp_dir = config["storage"]["temp_dir"]
        
        # 创建必要的目录
        for directory in [self.uploads_dir, self.output_dir, self.temp_dir]:
            os.makedirs(directory, exist_ok=True)
            logger.info(f"确保目录存在: {directory}")
            
        # 验证默认引擎是否可用
        try:
            EngineFactory.get_engine(self.default_engine, config)
            logger.info(f"文档服务初始化完成，默认引擎: {self.default_engine}")
        except Exception as e:
            available_engines = list(EngineFactory._engines.keys())
            logger.error(f"默认引擎 {self.default_engine} 不可用，已注册引擎: {available_engines}")
            if available_engines:
                self.default_engine = available_engines[0]
                logger.info(f"使用备选引擎: {self.default_engine}")
            else:
                raise ValueError("没有可用的文档处理引擎")
    
    async def process_document(
        self, 
        file: UploadFile, 
        parser_option: str = "default",
        image_option: str = "obs",
        engine_name: Optional[str] = None,
        unique_filename: Optional[str] = None
    ) -> Dict[str, Any]:
        """处理上传的文档
        
        Args:
            file: 上传的文件
            parser_option: 解析选项 ("default", "advanced" 或 "mineru")
            image_option: 图片处理选项 ("obs" 或 "remove")
            engine_name: 要使用的引擎名称，如果为None则使用默认引擎
            unique_filename: 唯一的文件名，如果为None则使用原始文件名
            
        Returns:
            处理结果字典，包含以下键:
                - file_name: 文件名
                - markdown: Markdown内容
                - temp_dir: 临时目录路径
        """
        logger.info(f"开始处理文档: {file.filename}, 选项: parser={parser_option}, image={image_option}")
        
        # 验证图片处理选项
        if image_option not in ["obs", "remove"]:
            logger.warning(f"不支持的图片处理选项: {image_option}，自动使用 obs 选项")
            image_option = "remove"
        
        # 如果没有指定引擎名称，则根据parser_option和文件类型确定
        if engine_name is None:
            file_ext = os.path.splitext(file.filename)[1].lower()
            
            # 根据解析选项选择引擎
            if parser_option == "marker":
                engine_name = "marker"
                logger.info("使用 marker 高级解析引擎")
            elif parser_option == "mineru":
                engine_name = "mineru"
                logger.info("使用 MinerU 高级解析引擎")
            elif parser_option == "advanced":
                if file_ext in ['.doc', '.docx']:
                    engine_name = "word"
                    logger.info(f"使用高级解析模式，根据文件类型选择Word引擎: {engine_name}")
                elif file_ext == '.pdf':
                    engine_name = "pdfminer"
                    logger.info(f"使用高级解析模式，根据文件类型选择PDF引擎: {engine_name}")
                else:
                    # 对于不支持的文件类型，降级使用默认引擎
                    engine_name = self.default_engine
                    logger.warning(f"高级解析模式不支持的文件格式: {file_ext}，降级使用默认引擎: {engine_name}")
            else:
                # 基础解析模式默认使用markitdown引擎
                engine_name = "markitdown"
                logger.info(f"使用基础解析模式，使用markitdown引擎")
            
        try:
            # 验证文件格式
            file_ext = os.path.splitext(file.filename)[1].lower()
            supported_formats = self.config["document"]["supported_formats"]
            
            if file_ext not in supported_formats:
                raise ValueError(f"不支持的文件格式: {file_ext}，支持的格式: {', '.join(supported_formats)}")
            
            # 获取引擎实例
            engine = EngineFactory.get_engine(engine_name, self.config)
            
            # 创建临时工作目录
            temp_work_dir = os.path.join(self.temp_dir, str(uuid.uuid4()))
            os.makedirs(temp_work_dir, exist_ok=True)
            logger.info(f"创建临时工作目录: {temp_work_dir}")
            
            try:
                # 保存上传的文件
                upload_path = os.path.join(self.uploads_dir, unique_filename or file.filename)
                with open(upload_path, "wb") as f:
                    content = await file.read()
                    f.write(content)
                file.file.seek(0)  # 重置文件指针以便重复读取
                
                # 生成唯一的Markdown文件名
                md_filename = unique_filename or file.filename
                md_base_name = os.path.splitext(md_filename)[0]
                
                # 转换文档为Markdown
                result = await engine.convert_to_markdown(
                    file.file, 
                    file.filename,
                    image_option,
                    work_dir=temp_work_dir,
                    md_filename=md_base_name  # 传递生成的Markdown文件名
                )
                
                # 处理图片 - 仅支持 obs 选项
                if image_option == "obs" and result["images"]:
                    # 处理图片（上传到OBS并更新Markdown引用）
                    result["markdown"] = await engine.handle_images(
                        result["images"],
                        result["markdown"],
                        self.obs_uploader
                    )
                
                # 保存Markdown文件
                markdown_file_path = await self._save_markdown(
                    result["markdown"], 
                    md_filename
                )
                
                return {
                    "file_name": unique_filename or file.filename,
                    "markdown": result["markdown"],
                    "markdown_file": markdown_file_path,
                    "temp_dir": temp_work_dir
                }
                
            except Exception as e:
                # 清理临时工作目录
                await self.cleanup_temp_files(temp_work_dir)
                raise
            
        except Exception as e:
            logger.error(f"处理文档失败: {str(e)}")
            raise
    
    async def cleanup_temp_files(self, temp_dir: str) -> None:
        """清理临时文件
        
        Args:
            temp_dir: 临时目录路径
            
        注意:
            现在临时文件不会立即清理，而是由文件清理服务按照配置的时间间隔（默认30分钟）自动清理。
            这样可以保留图片资源一段时间，同时避免文件系统占用过多空间。
        """
        try:
            # 不再清理临时目录，保留图片资源
            # if temp_dir and os.path.exists(temp_dir):
            #     shutil.rmtree(temp_dir, ignore_errors=True)
            #     logger.info(f"已清理临时目录: {temp_dir}")
            logger.info(f"保留临时目录: {temp_dir}，临时文件将在30分钟后由自动清理服务处理")
        except Exception as e:
            logger.error(f"处理临时文件失败: {str(e)}")
    
    async def _save_markdown(self, markdown_content: str, filename: str) -> str:
        """保存Markdown内容到文件
        
        Args:
            markdown_content: Markdown内容
            filename: 文件名（可以是原始文件名或唯一文件名）
            
        Returns:
            str: 保存的Markdown文件路径
        """
        # 创建输出目录
        output_dir = os.path.join(self.output_dir)
        os.makedirs(output_dir, exist_ok=True)
        
        # 生成Markdown文件名
        md_filename = os.path.splitext(filename)[0] + ".md"
        md_file_path = os.path.join(output_dir, md_filename)
        
        # 保存文件
        with open(md_file_path, "w", encoding="utf-8") as f:
            f.write(markdown_content)
        
        logger.info(f"已保存Markdown文件: {md_file_path}")
        return md_file_path 